/**
 * Copyright (c) 2011 ~ 2014 Deepin, Inc.
 *               2013 ~ 2014 jouyouyun
 *
 * Author:      jouyouyun <jouyouwen717@gmail.com>
 * Maintainer:  jouyouyun <jouyouwen717@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 **/

package main

import (
        "fmt"
        "github.com/howeyc/fsnotify"
        "os"
        "regexp"
        "sync"
        "time"
)

const TEST_DIR = "/Datas/TestDir"

var (
        watchCloseChan = make(chan bool)
        dirModChan     = make(chan bool)
        //dirWatchMap    = make(map[string]*fsnotify.Watcher)
        prevEventStr = ""
        mutex        = new(sync.Mutex)
        watchCount   = uint32(0)
)

func watchDir(dir string) {
        watcher, err := fsnotify.NewWatcher()
        if err != nil {
                fmt.Printf("New Watch Failed For Dir: '%s', Error: %v\n",
                        dir, err)
                return
        }

        if err := watcher.Watch(dir); err != nil {
                fmt.Printf("Watch '%s' Failed: %v\n", dir, err)
                watcher.Close()
                return
        }
        //fmt.Println("Watch Dir: ", dir)

        //dirWatchMap[dir] = watcher
        //mutex.Lock()
        watchCount += 1
        //fmt.Printf("Watch Count Add: %d\n\n", watchCount)
        //mutex.Unlock()
        go func() {
                defer func() {
                        if watcher != nil {
                                watcher.Close()
                        }
                        //delete(dirWatchMap, dir)
                        //mutex.Lock()
                        //fmt.Printf("Watch Count Delete: %d\n\n", watchCount)
                        watchCount -= 1
                        //mutex.Unlock()
                }()

                for {
                        select {
                        case ev := <-watcher.Event:
                                if ev == nil {
                                        break
                                }

                                if ok, _ := regexp.MatchString(`\.swa?px?$`,
                                        ev.Name); ok {
                                        break
                                }

                                fmt.Println("\nEvent: ", ev)
                                fmt.Printf("Prev Event: %s\n",
                                        prevEventStr)
                                if ev.IsCreate() || ev.IsDelete() {
                                        //if prevEventStr == ev.String() {
                                        //break
                                        //}

                                        prevEventStr = ev.String()
                                        fmt.Println("Emit Dir Modify")
                                        dirModChan <- true
                                        return
                                }
                        case err := <-watcher.Error:
                                if err == nil {
                                }
                                fmt.Println("Error: ", err)
                        case <-watchCloseChan:
                                return
                        }
                }
        }()
}

func startWatch(dir string) {
        //mutex.Lock()
        //defer mutex.Unlock()
        f, err := os.Open(dir)
        if err != nil {
                fmt.Printf("Open '%s' failed: %v\n", dir, err)
                return
        }
        defer f.Close()

        finfos, err1 := f.Readdir(0)
        if err1 != nil {
                fmt.Printf("Readdir '%s' failed: %v\n", dir, err1)
                return
        }

        watchDir(dir)
        for _, info := range finfos {
                if info == nil || !info.IsDir() {
                        continue
                }

                startWatch(dir + "/" + info.Name())
        }
}

func resetWatchDir(dir string) {
        for {
                select {
                case <-dirModChan:
                        //mutex.Lock()
                        fmt.Println("Reset Watchers. Count: ", watchCount)
                        //for d, w := range dirWatchMap {
                        //for _, _ = range dirWatchMap {
                        for i := uint32(0); i < watchCount; i++ {
                                //if w != nil {
                                //w.Close()
                                //}
                                //delete(dirWatchMap, d)
                                watchCloseChan <- true
                        }
                        <-time.After(time.Microsecond * 3000)
                        startWatch(dir)
                        //mutex.Unlock()
                }
        }
}

func main() {
        startWatch(TEST_DIR)
        go resetWatchDir(TEST_DIR)
        <-time.After(time.Microsecond * 3000)

        select {}
}
